package com.inspur.edp.cef.designtime.api.element.increment.merger;

import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.basic.ControlRuleItem;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlrule.cm.CommonFieldControlRule;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.basic.entity.ControlRuleDefItem;
import com.inspur.edp.cef.designtime.api.changecontrolrule.controlruledef.cm.CommonFieldContrulRuleDef;
import com.inspur.edp.cef.designtime.api.collection.GspAssociationCollection;
import com.inspur.edp.cef.designtime.api.collection.GspEnumValueCollection;
import com.inspur.edp.cef.designtime.api.collection.GspFieldCollection;
import com.inspur.edp.cef.designtime.api.element.*;
import com.inspur.edp.cef.designtime.api.element.increment.GspCommonFieldIncrement;
import com.inspur.edp.cef.designtime.api.element.increment.ModifyFieldIncrement;
import com.inspur.edp.cef.designtime.api.entity.GspCommonDataType;
import com.inspur.edp.cef.designtime.api.entity.GspCommonField;
import com.inspur.edp.cef.designtime.api.entity.MappingRelation;
import com.inspur.edp.cef.designtime.api.increment.IncrementType;
import com.inspur.edp.cef.designtime.api.increment.extractor.ExtractUtils;
import com.inspur.edp.cef.designtime.api.increment.extractor.MonkControlRule;
import com.inspur.edp.cef.designtime.api.increment.merger.AbstractIncrementMerger;
import com.inspur.edp.cef.designtime.api.increment.merger.MergeUtils;
import com.inspur.edp.cef.designtime.api.increment.property.*;
import com.inspur.edp.cef.designtime.api.json.CefNames;
import java.util.ArrayList;
import lombok.var;

import javax.lang.model.util.ElementScanner6;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * The Definition Of DimensionInfo
 *
 * @ClassName: DimensionInfo
 * @Author: Benjamin Gong
 * @Date: 2021/1/11 17:13
 * @Version: V1.0
 */
public class CommonFieldIncrementMerger extends AbstractIncrementMerger {

    protected boolean includeAll;

    public CommonFieldIncrementMerger(){

    }

    public CommonFieldIncrementMerger(boolean includeAll){
        this.includeAll = includeAll;
    }

    public GspCommonField merge(
            GspCommonField extendField,
            GspCommonFieldIncrement extendIncrement,
            GspCommonFieldIncrement baseIncrement,
            CommonFieldControlRule rule,
            CommonFieldContrulRuleDef def) {

        if (baseIncrement.getIncrementType() == IncrementType.Modify)
            return mergeModifyIncrement(extendField, (ModifyFieldIncrement) extendIncrement, (ModifyFieldIncrement) baseIncrement, rule, def);
        return null;
    }


    private GspCommonField mergeModifyIncrement(
            GspCommonField extendField,
            ModifyFieldIncrement extendIncrement,
            ModifyFieldIncrement baseIncrement,
            CommonFieldControlRule rule,
            CommonFieldContrulRuleDef def) {

        var propChanges = baseIncrement.getChangeProperties();
        if (propChanges.size() > 0) {
            mergeChangeProps(extendField, extendIncrement == null ? null:extendIncrement.getChangeProperties(), propChanges, rule, def);
        }

        mergeExtendField(extendField, extendIncrement, baseIncrement, rule, def);
        return extendField;
    }


    private void mergeChangeProps(
            GspCommonField extendField,
            HashMap<String, PropertyIncrement> extendIncrement,
            HashMap<String, PropertyIncrement> baseIncrement,
            CommonFieldControlRule rule,
            CommonFieldContrulRuleDef def) {

        if(includeAll){
            mergeAllProps(extendField, extendIncrement, baseIncrement);
            return;
        }
        //todo 处理扩展字段属性修改后的同步，目前仅支持默认值以及默认值类型
        if(extendField.getCustomizationInfo()!=null && extendField.getCustomizationInfo().isCustomized()){
            mergeExtendField(extendField,extendIncrement,baseIncrement);
            return;
        }
        if (rule == null || def == null) {
            return;
        }
        if (baseIncrement.containsKey(CefNames.Name)) {
            String mergedName = MergeUtils.getStringValue(
                    CefNames.Name,
                    (StringPropertyIncrement)baseIncrement.get(CefNames.Name),
                    extendIncrement,
                    rule.getNameControlRule(),
                    def.getNameControlRule());
            extendField.setName(mergedName);
        }
        if (baseIncrement.containsKey(CefNames.DefaultValue)) {
            String mergedName = MergeUtils.getStringValue(
                    CefNames.DefaultValue,
                    (StringPropertyIncrement)baseIncrement.get(CefNames.DefaultValue),
                    extendIncrement,
                    rule.getDefaultValueControlRule(),
                    def.getDefaultValueControlRule());
            extendField.setDefaultValue(mergedName);
            dealChangedProperties(extendField,CefNames.DefaultValue);
        }
        if (baseIncrement.containsKey(CefNames.DefaultValueType)) {
            Object mergedValueType = MergeUtils.getObjectValue(
                    CefNames.DefaultValueType,
                    (ObjectPropertyIncrement) baseIncrement.get(CefNames.DefaultValueType),
                    extendIncrement,
                    rule.getDefaultValueControlRule(),
                    def.getDefaultValueControlRule());
            if (mergedValueType instanceof String) {
                mergedValueType = ElementDefaultVauleType.valueOf(mergedValueType.toString());
            } else if (mergedValueType instanceof ElementDefaultVauleType) {
                mergedValueType = (ElementDefaultVauleType)mergedValueType;
            }
            extendField.setDefaultValueType((ElementDefaultVauleType) mergedValueType);
        }
        if (baseIncrement.containsKey(CefNames.Length)) {
            int intValue = (int) ((IntPropertyIncrement)baseIncrement.get(CefNames.Length)).getPropertyValue();
            extendField.setLength(intValue);
        }

        if (baseIncrement.containsKey(CefNames.Precision)) {
            int intValue = MergeUtils.getIntValueAllowShort(
                    CefNames.Precision,
                    (IntPropertyIncrement)baseIncrement.get(CefNames.Precision),
                    extendIncrement,
                    rule.getPrecisionControlRule(),
                    def.getPrecisionControlRule());
            extendField.setPrecision(intValue);
        }
        if (baseIncrement.containsKey(CefNames.ContainEnumValues))
            mergeEnumValues(extendField,extendIncrement,baseIncrement,rule,def);
    }
    private void mergeEnumValues(GspCommonField extendField, HashMap<String, PropertyIncrement> extendIncrement, HashMap<String, PropertyIncrement> baseIncrement,
                                 CommonFieldControlRule rule, CommonFieldContrulRuleDef def){{
            ObjectPropertyIncrement objectIncrement =  (ObjectPropertyIncrement) baseIncrement.get(CefNames.ContainEnumValues);
            GspEnumValueCollection mergedEnums = (GspEnumValueCollection)MergeUtils.getObjectValue("ContainEnumValues", (ObjectPropertyIncrement)objectIncrement, (HashMap)null, (ControlRuleItem)null, (ControlRuleDefItem)null);
            extendField.setContainEnumValues(mergedEnums);
        }
    }
    private void mergeExtendField(GspCommonField extendField, HashMap<String, PropertyIncrement> extendIncrement, HashMap<String, PropertyIncrement> baseIncrement) {
        if (baseIncrement.containsKey(CefNames.DefaultValue)) {
            StringPropertyIncrement increment=((StringPropertyIncrement)baseIncrement.get(CefNames.DefaultValue));
            if(increment!=null){
                Object mergedValue=increment.getPropertyValue();
                String value=mergedValue==null? null:mergedValue.toString();
                extendField.setDefaultValue(value);
            }
        }
        if (baseIncrement.containsKey(CefNames.DefaultValueType)) {
            ObjectPropertyIncrement objectIncrement =  (ObjectPropertyIncrement) baseIncrement.get(CefNames.DefaultValueType);
            Object mergedValueType=objectIncrement.getPropertyValue();
            if (mergedValueType instanceof String) {
                mergedValueType = ElementDefaultVauleType.valueOf(mergedValueType.toString());
            } else if (mergedValueType instanceof ElementDefaultVauleType) {
                mergedValueType = (ElementDefaultVauleType)mergedValueType;
            }
            extendField.setDefaultValueType((ElementDefaultVauleType) mergedValueType);
        }
        if (baseIncrement.containsKey(CefNames.ContainEnumValues)) {
            ObjectPropertyIncrement objectIncrement =  (ObjectPropertyIncrement) baseIncrement.get(CefNames.ContainEnumValues);
            GspEnumValueCollection mergedEnums = (GspEnumValueCollection)MergeUtils.getObjectValue("ContainEnumValues", (ObjectPropertyIncrement)objectIncrement, (HashMap)null, (ControlRuleItem)null, (ControlRuleDefItem)null);
            extendField.setContainEnumValues(mergedEnums);
        }

    }

    private void mergeAllProps(
            GspCommonField extendField,
            HashMap<String, PropertyIncrement> extendIncrement,
            HashMap<String, PropertyIncrement> baseIncrement){
        for(var incrementPair : baseIncrement.entrySet()){
            String key = incrementPair.getKey();
            PropertyIncrement increment = incrementPair.getValue();
            dealChangeProp(extendField, extendIncrement, key, increment);
        }
    }
    private void dealChangedProperties(IGspCommonField field,String value){
        if(field.getChangedProperties()==null)
            field.setChangedProperties(new ArrayList<String>(){{add(value);}});
        if(!field.getChangedProperties().contains(value)){
            field.getChangedProperties().add(value);
        }
    }
    private void dealChangeProp(GspCommonField extendField, HashMap<String, PropertyIncrement> extendIncrement, String key, PropertyIncrement increment){
        switch (key){
            case CefNames.Name:
                String mergedName = MergeUtils.getStringValue(CefNames.Name, (StringPropertyIncrement)increment, extendIncrement, null,null);
                extendField.setName(mergedName);
                return;
            case CefNames.DefaultValue:
                String mergedDefaultValue = MergeUtils.getStringValue(CefNames.DefaultValue, (StringPropertyIncrement)increment, extendIncrement, null,null);
                extendField.setDefaultValue(mergedDefaultValue);
                dealChangedProperties(extendField,CefNames.DefaultValue);
                return;
            case CefNames.Length:
                int mergedLength = (int) ((IntPropertyIncrement) increment).getPropertyValue();
                extendField.setLength(mergedLength);
                return;
            case CefNames.Precision:
                int mergedPrecision = MergeUtils.getIntValue(CefNames.Precision, (IntPropertyIncrement)increment, extendIncrement, null,null);
                extendField.setPrecision(mergedPrecision);
                return;
            case CefNames.LabelID:
                String mergedLabelID = MergeUtils.getStringValue(CefNames.LabelID, (StringPropertyIncrement)increment, null, null,null);
                extendField.setLabelID(mergedLabelID);
                return;
            case CefNames.IsRef:
                boolean mergedIsRef = MergeUtils.getBooleanValue(CefNames.IsRef, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsRef(mergedIsRef);
                return;
            case CefNames.I18nResourceInfoPrefix:
                String mergedI18n = MergeUtils.getStringValue(CefNames.I18nResourceInfoPrefix, (StringPropertyIncrement)increment, null, null,null);
                extendField.setI18nResourceInfoPrefix(mergedI18n);
                return;
            case CefNames.Code:
                String mergedCode = MergeUtils.getStringValue(CefNames.Code, (StringPropertyIncrement)increment, null, null,null);
                extendField.setCode(mergedCode);
                return;
            case CefNames.IsRequire:
                boolean mergedIsRequire = MergeUtils.getBooleanValue(CefNames.IsRequire, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsRequire(mergedIsRequire);
                return;
            case CefNames.IsMultiLanguage:
                boolean mergedMul = MergeUtils.getBooleanValue(CefNames.IsMultiLanguage, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsMultiLanguage(mergedMul);
                return;
            case CefNames.IsRefElement:
                boolean mergedRefEle = MergeUtils.getBooleanValue(CefNames.IsRefElement, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsRefElement(mergedRefEle);
                return;
            case CefNames.IsUdt:
                boolean mergedIsUdt = MergeUtils.getBooleanValue(CefNames.IsUdt, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsUdt(mergedIsUdt);
                return;
            case CefNames.UdtPkgName:
                String mergedUdtPkgName = MergeUtils.getStringValue(CefNames.UdtPkgName, (StringPropertyIncrement)increment, null, null,null);
                extendField.setUdtPkgName(mergedUdtPkgName);
                return;
            case CefNames.UdtID:
                String mergedUdtID = MergeUtils.getStringValue(CefNames.UdtID, (StringPropertyIncrement)increment, null, null,null);
                extendField.setUdtID(mergedUdtID);
                return;
            case CefNames.UdtName:
                String mergedUdtName = MergeUtils.getStringValue(CefNames.UdtName, (StringPropertyIncrement)increment, null, null,null);
                extendField.setUdtName(mergedUdtName);
                return;
            case CefNames.IsVirtual:
                boolean mergedIsVirtual = MergeUtils.getBooleanValue(CefNames.IsVirtual, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsVirtual(mergedIsVirtual);
                return;
            case CefNames.BeLabel:
                List<String> mergedBeLabel = MergeUtils.getObjectValue(CefNames.BeLabel, (ObjectPropertyIncrement)increment, null, null,null);
                extendField.setBeLabel(mergedBeLabel);
                return;
            case CefNames.IsFromAssoUdt:
                boolean mergedIsFromAssoUdt = MergeUtils.getBooleanValue(CefNames.IsFromAssoUdt, (BooleanPropertyIncrement)increment, null, null,null);
                extendField.setIsUdt(mergedIsFromAssoUdt);
                return;
            case CefNames.EnumIndexType:
                Object enumIndexVal = MergeUtils.getObjectValue(CefNames.EnumIndexType, (ObjectPropertyIncrement)increment, null, null,null);
                EnumIndexType mergedEnumIndexType = null;
                if(enumIndexVal instanceof String)
                    mergedEnumIndexType = EnumIndexType.valueOf(enumIndexVal.toString());
                else if(enumIndexVal instanceof EnumIndexType)
                    mergedEnumIndexType = (EnumIndexType)enumIndexVal;

                extendField.setEnumIndexType(mergedEnumIndexType);
                return;
            case CefNames.CollectionType:
                Object colTypeVal = MergeUtils.getObjectValue(CefNames.CollectionType, (ObjectPropertyIncrement)increment, null, null,null);
                FieldCollectionType mergedCollectionType = null;
                if(colTypeVal instanceof String)
                    mergedCollectionType = FieldCollectionType.valueOf(colTypeVal.toString());
                else if(colTypeVal instanceof FieldCollectionType)
                    mergedCollectionType = (FieldCollectionType)colTypeVal;
                extendField.setCollectionType(mergedCollectionType);
                return;
            case CefNames.ObjectType:
                Object objectTypeVal = MergeUtils.getObjectValue(CefNames.ObjectType, (ObjectPropertyIncrement)increment, null, null,null);
                GspElementObjectType mergedObjectType = null;
                if(objectTypeVal instanceof String)
                    mergedObjectType = GspElementObjectType.valueOf(objectTypeVal.toString());
                else if(objectTypeVal instanceof GspElementObjectType)
                    mergedObjectType = (GspElementObjectType)objectTypeVal;
                extendField.setObjectType(mergedObjectType);
                return;
            case CefNames.MDataType:
                Object mdTypeVal = MergeUtils.getObjectValue(CefNames.MDataType, (ObjectPropertyIncrement)increment, null, null,null);
                GspElementDataType mergedMDataType = null;
                if(mdTypeVal instanceof String)
                    mergedMDataType = GspElementDataType.valueOf(mdTypeVal.toString());
                else if(mdTypeVal instanceof GspElementDataType)
                    mergedMDataType = (GspElementDataType)mdTypeVal;
                extendField.setMDataType(mergedMDataType);
                return;
            case CefNames.DefaultValueType:
                Object dvTypeVal = MergeUtils.getObjectValue(CefNames.DefaultValueType, (ObjectPropertyIncrement)increment, null, null,null);
                ElementDefaultVauleType mergedDefaultValueType = null;
                if(dvTypeVal instanceof String)
                    mergedDefaultValueType = ElementDefaultVauleType.valueOf(dvTypeVal.toString());
                else if(dvTypeVal instanceof ElementDefaultVauleType)
                    mergedDefaultValueType = (ElementDefaultVauleType)dvTypeVal;
                extendField.setDefaultValueType(mergedDefaultValueType);
//                dealChangedProperties(extendField,CefNames.DefaultValueType);
                return;
            case CefNames.MappingRelation:
                MappingRelation mergedMappingRelation = MergeUtils.getObjectValue(CefNames.MappingRelation, (ObjectPropertyIncrement)increment, null, null,null);
                extendField.setMappingRelation(mergedMappingRelation);
                return;
            case CefNames.ContainEnumValues:
                GspEnumValueCollection mergedEnums = MergeUtils.getObjectValue(CefNames.ContainEnumValues, (ObjectPropertyIncrement)increment, null, null,null);
                extendField.setContainEnumValues(mergedEnums);
                return;
//            case CefNames.ChildElements:
//                GspFieldCollection mergedChildElements = MergeUtils.getObjectValue(CefNames.ChildElements, (ObjectPropertyIncrement)increment, null, null,null);
//                extendField.setChildElements(mergedChildElements);
//                return;
            case CefNames.ChildAssociations:
                GspAssociationCollection mergedAsso = MergeUtils.getObjectValue(CefNames.ChildAssociations, (ObjectPropertyIncrement)increment, null, null,null);
                extendField.setChildAssociations(mergedAsso);
                return;

        }
        dealExtendChangeProp(extendField, extendIncrement, key, increment);
    }

    protected void dealExtendChangeProp(GspCommonField extendField, HashMap<String, PropertyIncrement> extendIncrement, String key, PropertyIncrement increment){

    }
    protected void mergeExtendField(
            GspCommonField extendField,
            ModifyFieldIncrement extendIncrement,
            ModifyFieldIncrement baseIncrement,
            CommonFieldControlRule rule,
            CommonFieldContrulRuleDef def){

    }
}
